package core;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import persistence.DataPersistor;

import core.exception.IllegalAddException;
import core.exception.IllegalEditException;
import core.exception.IllegalMoveException;
import core.exception.NotFoundException;
import core.exception.SaveException;

public class ProductFacadeTest {
	//TODO: write tests for all the canSet methods
	static ItemFacade iFacade;
	static ContainerFacade cFacade;
	static ProductFacade pFacade;
	static Container testSU;
	static Container testG1;
	static Container testG2;
	static Product testP;
	static Item testI1, testI2;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		testP = new Product(new Barcode("512345123459", BarcodeType.PRODUCT),
				"A test Product.",
				new Amount(3.59F, UnitOfMeasurement.kilograms),
				6, 9);
		DataPersistor.instance().init("-serial");
		ItemManager.setInstance(null);
		ProductManager.setInstance(null);
		RootStorageUnit.setInstance(null);
		ItemFacade.setInstance(null);
		ProductFacade.setInstance(null);
		ContainerFacade.setInstance(null);

	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		testP = null;
	}

	@Before
	public void setUp() throws Exception {
		iFacade = ItemFacade.instance();
		pFacade = ProductFacade.instance();
		cFacade = ContainerFacade.instance();
		cFacade.addStorageUnit("TestSU");
		testSU = cFacade.get_rootUnit().lookupContainer("TestSU");
		testSU.addContainer("TestG1");
		testG1 = testSU.lookupContainer("TestG1");
		testSU.addContainer("TestG2");
		testG2 = testSU.lookupContainer("TestG2");
		//testG1.addProduct(testP);
		//testG2.addProduct(testP);
		testI1 = new Item(testP, new Barcode("41000000004", BarcodeType.ITEM));
		testI2 = new Item(testP, new Barcode("41234512345", BarcodeType.ITEM));
		//testG1.addItem(testI1);
		//testG1.addItem(testI2);
	}

	@After
	public void tearDown() throws Exception {
		ItemManager.setInstance(null);
		ProductManager.setInstance(null);
		RootStorageUnit.setInstance(null);
		ItemFacade.setInstance(null);
		ProductFacade.setInstance(null);
		ContainerFacade.setInstance(null);
	}

	@Test
	public void testCanAddProduct() {
		assertTrue(pFacade.canAddProduct(testP, testG1));
		assertFalse(pFacade.canAddProduct(null, testG1));
		
	}

	@Test
	public void testAddProduct() {
		assertFalse(testG1.containsProduct(testP));
		try {
			pFacade.createProduct(testP, testG1);
		} catch (IllegalAddException e) {
			e.printStackTrace();
			fail("IllegalAddException");
		}
		assertTrue(testG1.containsProduct(testP));
		
		try {
			pFacade.removeProduct(testP, testG1);
		} catch (SaveException e) {
			e.printStackTrace();
			fail("IllegalRemoveException");
		}
	}

	@Test
	public void testCanRemoveProduct() {
		assertFalse(pFacade.canRemoveProduct(null, testG1));
		assertFalse(pFacade.canRemoveProduct(testP, testG1));
		try {
			pFacade.createProduct(testP, testG1);
		} catch (IllegalAddException e) {
			e.printStackTrace();
			fail("IllegalAddException");
		}
		assertTrue(pFacade.canRemoveProduct(testP, testG1));
	}

	@Test
	public void testRemoveProduct() {
		assertFalse(testG1.containsProduct(testP));
		try {
			pFacade.createProduct(testP, testG1);
		} catch (IllegalAddException e) {
			e.printStackTrace();
			fail("IllegalAddException");
		}
		assertTrue(testG1.containsProduct(testP));
		
		try {
			pFacade.removeProduct(testP, testG1);
		} catch (SaveException e) {
			e.printStackTrace();
			fail("IllegalRemoveException");
		}
		assertFalse(testG1.containsProduct(testP));
	}

	@Test
	public void testMoveProduct() {
		assertFalse(testG1.containsProduct(testP));

		try {
			pFacade.createProduct(testP, testG1);
		} catch (IllegalAddException e) {
			e.printStackTrace();
			fail("IllegalAddException");
		}
		
		assertTrue(testG1.containsProduct(testP));
		assertFalse(testG2.containsProduct(testP));
		
		try {
			pFacade.moveProduct(testP, testG1, testG2);
		} catch (IllegalMoveException e) {
			e.printStackTrace();
			fail("IllegalMoveException");
		} catch (NotFoundException e) {
			e.printStackTrace();
			fail("NotFoundException");
		}
		
		assertFalse(testG1.containsProduct(testP));
		assertTrue(testG2.containsProduct(testP));
	}

	@SuppressWarnings("deprecation")
	@Test
	public void testCanEditProduct() {
		assertTrue(pFacade.canEditProduct(testP, testP.getBarcode(), 
				"Something Different", testP.getSize(), 31, 94));
		assertFalse(pFacade.canEditProduct(testP, testP.getBarcode(), 
				"Something Different", testP.getSize(), -1, -1));
	}

	@SuppressWarnings("deprecation")
	@Test
	public void testEditProduct() {
		try {
			pFacade.editProduct(testP, testP.getBarcode(), 
					"Something Different", testP.getSize(), 31, 94);
		} catch (IllegalEditException e) {
			e.printStackTrace();
			fail("IllegalEditException");
		} catch (NotFoundException e) {
			e.printStackTrace();
			fail("NotFoundException");
		}
		
		assertEquals("Something Different", testP.getDescription());
		assertEquals(31, testP.getShelfLife());
		assertEquals(94, testP.getThreeMonthSupply());
	}

}
